1

此文优先发布于我的个人博客:TB+TableLayout+Fragment+VP开发实践

研究ToolBar、TabLayout、Fragment+ViewPager的开发实践复盘以及尚未解决的问题。欢迎评论留言。

XML

TabLayout

添加依赖

'android.support.design:28.0.0'

此处添加AppBarLayout作为完整的布局1:

AppBarLayout是Android Design Support Library新加的控件继承自LinearLayout,
它用来将Toolbar和TabLayout组合起来作为一个整体。
<android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
    
<android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways" //滑动隐藏功能
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
<android.support.design.widget.TabLayout
          android:id="@+id/main_tablayout"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"         
          android:background="@color/color_title_bar"/>

<android.support.v4.view.ViewPager <!--TabLayout相关联的ViewPager-->
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="@android:color/white" />

TabLayout可选属性

tab
可更改属性属性说明
tabBackgroundTabLayout的背景
tabSelectedTextColor当前标签的字体颜色
tabIndicator

可以写一个style,下文中会提到

可更改属性属性说明
tabIndicatorColor选中线的颜色
tabIndicatorHeight选中线的高度
tabMode
可更改属性属性说明
FIXED不可左右滑动,用于标签较少时
SCROLLABLE可左右滑动,用于标签较多时

Fragment

为什么要创建Fragment:TabLayout中的ViewPager对应着相应的Fragment,所以需要创建。

有的示例仅创建了一个Fragment,其中为定义文字数组实现,若开发中则需要多个Fragment添加,均用Arratlist于Activity中。

XXXFragment.java:

public class XXXFragment extends Fragment {
    
    private Page/View;  //创建变量
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //mPage = getArguments().getInt(ARG_PAGE);
    }
 
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_page, container, false);
        TextView textView = (TextView) view; //参考[^6]
        textView.setText("Fragment #" + mPage); 
        return view;
    }
 
}

一些暂未明确的代码段

 public static final String TYPE = "TYPE"; //此处未知含义

参考2

//此处的含义可能是新增实例,存储值?
    public static XXXFragment newInstance(int page) { 
        Bundle args = new Bundle();
        args.putInt(ARG_PAGE, page);
        PageFragment pageFragment = new PageFragment();
        pageFragment.setArguments(args);
        return pageFragment;
    }

Activity

如果需要定义TableLayout的tab文字,则在其中定义:public static final String[] titles,之后添加集合。

这里把2定义文字放在了Adapter中,原因未知。

关于添加图片,下文有提到。

    private Toolbar toolbar; //增加相关变量
    private TabLayout tabLayout;
    private ViewPager viewPager;

    public static final String[] titles = {"", ""};

    private List<Fragment> fragments; //定义fragment的集合缩写
    private List<String> tabNames;
    private List<Integer> tabIcs;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_xxx);
        initView();        //各种初始化:界面、添加的fragment值、事件
        initValue();
        initEvent();
    }

    //各种初始化开始

    private void initView() { //初始化实例

        toolbar = (Toolbar) findViewById(R.id.Toolbar); 
        setSupportActionBar(toolbar); //支持actionbar,此处多种写法
        getSupportActionBar().setDisplayHomeAsUpEnabled(true); //在首页显示

        viewPager = (ViewPager) findViewById(R.id.viewpager); //实例化控件
        tabLayout = (TabLayout) findViewById(R.id.tabs);
    }

    private void initValue() { 
    //初始化值,添加每一个TableLayout里的ArrayList,设置与标题栏一一对应的视图(片段)集合

        fragments = new ArrayList<>();
        fragments.add(new xxxFragment());
        fragments.add(new xxxFragment()); //有多少个fragment就在这里添加多少

        tabNames = new ArrayList<>(); //添加标题集合,同上
        tabNames.add(" ");
        tabNames.add(" ");

        /*tabIcs = new ArrayList<>(); 此处尚不明确是否有,使用spanstring或其他方法此处是否需要
        tabIcs.add(R.drawable.tab_xxx);
        tabIcs.add(R.drawable.tab_xxx);*/
        
        //给tabLayout添加选项卡
        for(int i=0;i< fragments.size();i++){
            tabLayout.addTab(tabLayout.newTab().setText((CharSequence) fragments.get(i)));
        }

        FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter
        (getSupportFragmentManager(), fragments, tabNames,tabIcs); 
        // 初始化ViewPager适配器        //此处需要增加与添加的集合以及上述定义的值匹配,若未定义则无需添加

        viewPager.setAdapter(adapter); //给ViewPager设置适配器
        tabLayout.setupWithViewPager(viewPager);  //将TabLayout和ViewPager关联起来      
        /*setupWithViewPager这个方法会先将tab清除然后再根据ViewPager的adapter里的count去取pagetitle,这也就是有时遇到用addTab方法添加tab不起作用的问题。*/

        //setupTabIcons();
        viewPager.setCurrentItem(1);
        viewPager.setCurrentItem(0);
    }

此处的setupTabIcons()方法,在下文添加图片会提到。[参考链接]()

默认显示第一个Tab3

tab.addTab(tab,i == 0, ? true:false);

FragmentPagerAdapter

需要使用Fragment的话就需要这个适配器

public class一个自定义的适配器名称继承自FragmentPagerAdapter。

    List<Fragment> xxxfragment;
    List<String> titleList;

public MyTableViewAdapter(FragmentManager fm , List<Fragment> pagerList , List<String> titleList) {
        super(fm);
    this.pagerList = pagerList; // 此处使用this.与上述定义匹配
  
}
    
public Fragment getItem(int poition)
    super.

public int getCount(int poition) { return (tab个数) } 
   return xxxfragment.get(position); //普通情况
   return xxxfragment != null ? pagerList.size() : 0; //设置不等于null的情况,参考[^4]

public long getItemId(int poition)  { return super.getItemId(position) }
return xxxfragment.get(position);

此处可能还有,参考 3

public destoryItemId(View view contain,int poition,Object object)

点击切换Tab的操作(两种方式)

  1. .setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 方法3

当tab页面被选中时,会调用这个方法,当tab页面被选中时,切换目前的fragment:

@Override
public void onTabSelected(TabLayout.Tab tab) {
int position = tab.getPosition();
    
Fragment fragment = (Fragment)adapter.instantiateItem(container, position);
    
adapter.setPrimaryItem(container, pos, fragment);
adapter.finishUpdate(container);
    
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
  1. 使用selector代替4

高级

在TabLayout中添加图片

方法

getTabView()4

此方法为我首先尝试使用,可以更改图标颜色以及状态。

步骤:

  1. 在Activity.java中设置图片点击(使用selector)数组public int[]
  2. 设置setupTabIcons();
  3. 创建getTabView()方法

这里52把此方法放到了FragmentAdapter中,个人猜测原因可能是一同将getTabView()或imagespan使用。

SpannableString

更多支持:介绍参考链接6

SpannableString这个类实现了CharSequence这个接口,所以可以在Adapter中的getPageTitle()中返回。

SpannableString的构造方法需要一个参数:CharSequence(超级字符串的基本显示内容),

setSpan为核心方法

方法值:

public void setSpan(Object what, int start, int end, int flags) {
    super.setSpan(what, start, end, flags);
          //what:向这个超级字符串中添加的内容。例如:前景色、背景色、图片、链接、下划线等
          //start:开始的位置(0为开始)
          //结束的位置
          //flags:标识在span范围内的文本前后输入新的字符时是否也应用这个效果
}

SpanString举例由于众多,表格与文末7

经搜索:

其中使用ImageSpan的两种方法,发现以下两种均为仅添加图标方法,而不适用于点击切换颜色:

使用SpanString和Imagespan:2
  1. 在SimpleFragmentPagerAdapter中设置数组int[]
  2. 样式文件定义
保留字符串并设置空,添加图片方法8
  1. 修改Adapter的构造方法:设置tabName和tabIcons变量:每个Tab上的文字和图标的变量
  2. 修改getPageTitle()方法:if-else语句:如果不设置文字,则保留一个字符,如果设置图标,则使用span
  3. 添加定义style(关键):textAllCaps、android:textAllCaps必须设置为false,之后XML中TabLayout设置style。

SpanString举例,示例代码7,项目完整地址9.

可更改属性属性说明
AbsoluteSizeSpan单位为物理像素
AlignmentSpan支持ALIGN_NORMAL,ALIGN_OPPOSITE,ALIGN_CENTER
BackgroundColorSpan文字背景色改变
BulletSpan小圆圈
ClickableSpan可点击
DrawableMarginSpanDrawable,不占位
DynamicDrawableSpanDynamicDrawable,占位
ForegroundColorSpan前景色
IconMarginSpan图标margin,不占位
ImageSpan图片,占位
LeadingMarginSpan控制行前空隙
QuoteSpan左侧出现引用符号 竖线
RelativeSizeSpan字体放大
ScaleXSpan字体宽度放大
StrikethroughSpan删除线
StyleSpan主要由正常、粗体、斜体和同时加粗倾斜四种样式,常量值定义在Typeface类中
SubscriptSpan下标
SuperscriptSpan上标
TextAppearanceSpanSets the text color, size, style, and typeface to match a TextAppearance
TypefaceSpan字体设置
UnderlineSpan下划线
URLSpanURL


故事熊
85 声望3 粉丝

对技术实现狂热的独立产品。